package org.piggy.core.filter.loadbalance.rule;

import org.piggy.common.config.ServiceInstance;
import org.piggy.common.enums.ResponseCode;
import org.piggy.common.exception.PiggyException;
import org.piggy.common.rule.Rule;
import org.piggy.core.algorithm.ConsistentHash;
import org.piggy.core.context.GatewayContext;
import org.piggy.core.manager.DynamicConfigManager;
import org.piggy.core.request.GatewayRequest;
import java.util.Set;

public class ConsistentHashLoadBalanceRule implements LoadBalanceGatewayRule {

    private ConsistentHashLoadBalanceRule(){}

    private static final ConsistentHashLoadBalanceRule consistentHashLoadBalanceRule = new ConsistentHashLoadBalanceRule();

    public static LoadBalanceGatewayRule getInstance (){
        return consistentHashLoadBalanceRule;
    }

    @Override
    public ServiceInstance choose(GatewayContext context) {
        return secondVersion(context);
    }

    public ServiceInstance firstVersion(GatewayContext context) {
        GatewayRequest request = context.getGatewayRequest();
        Rule rule = context.getRule();
        Set<ServiceInstance> set = DynamicConfigManager.getInstance().getServiceInstanceByServiceName(rule.getServiceName(), context.isGray());
        if(set.isEmpty()){
            throw new PiggyException(ResponseCode.SERVICE_INSTANCE_NOT_FOUND);
        }
        ConsistentHash consistentHash = new ConsistentHash();
        for(ServiceInstance s : set){
            consistentHash.addNode(s.getServiceInstanceId());
        }
        String node = consistentHash.getNode(request.getClientIp());
        if(node != null){
            for(ServiceInstance s : set){
                if(node.equals(s.getServiceInstanceId())){
                    return s;
                }
            }
        }
        return set.iterator().next();
    }

    public ServiceInstance secondVersion(GatewayContext context) {
        GatewayRequest request = context.getGatewayRequest();
        Rule rule = context.getRule();
        boolean gray = context.isGray();
        Set<ServiceInstance> set = DynamicConfigManager.getInstance().getServiceInstanceByServiceName(rule.getServiceName(), gray);
        if(set.isEmpty()){
            throw new PiggyException(ResponseCode.SERVICE_INSTANCE_NOT_FOUND);
        }
        ConsistentHash consistentHash = DynamicConfigManager.getInstance().getConsistentHashByServiceName(rule.getServiceName(), gray);
        String node = consistentHash.getNode(request.getClientIp());
        if(node != null){
            for(ServiceInstance s : set){
                if(node.equals(s.getServiceInstanceId())){
                    return s;
                }
            }
        }
        throw new PiggyException(ResponseCode.SERVICE_INSTANCE_NOT_FOUND);
    }

}
